package com.meida.module.arc.provider.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaSave;
import com.meida.common.mybatis.query.CriteriaUpdate;
import com.meida.common.utils.ApiAssert;
import com.meida.common.utils.RedisUtils;
import com.meida.module.arc.client.constants.ArchiveConstants;
import com.meida.module.arc.client.entity.ArcSetting;
import com.meida.module.arc.client.enums.ArchiveEnumInteger;
import com.meida.module.arc.client.utils.ArcUtils;
import com.meida.module.arc.provider.mapper.ArcSettingMapper;
import com.meida.module.arc.provider.service.ArcAuthTokenService;
import com.meida.module.arc.provider.service.ArcSettingService;
import com.meida.module.virbox.provider.AuthTokenProvider;
import com.meida.module.virbox.provider.entity.AuthToken;
import com.meida.module.virbox.provider.tokenProvider.jwt.H265JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 系统配置接口实现类
 *
 * @author flyme
 * @date 2021-11-18
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ArcSettingServiceImpl extends BaseServiceImpl<ArcSettingMapper, ArcSetting> implements ArcSettingService {

    @Autowired
    private ArcAuthTokenService arcAuthTokenService;

    @Autowired
    private AuthTokenProvider authTokenProvider;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private ArcSettingService arcSettingService;

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, ArcSetting setting, EntityMap extra) {
        return ResultBody.ok();
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<ArcSetting> cq, ArcSetting setting, EntityMap requestMap) {
        cq.orderByDesc("setting.createTime");
        return ResultBody.ok();
    }


    @Override
    public ResultBody beforeEdit(CriteriaUpdate cu, ArcSetting t, EntityMap extra) {
        ArcSetting setting = this.getById(t.getSettingId());
        if (FlymeUtils.isNotEmpty(t.getToken()) && !t.getToken().equals(setting.getToken())) {
            String idCode = checkIdCode(t.getIdCode(), t.getSettingId());
            if (!idCode.equals(t.getIdCode())) {
                t.setIdCode(idCode);
            }
            ApiAssert.isNotEmpty("获取机器码失败", idCode);
            String code = null;
            try {
                code = H265JwtUtils.paseJWT(idCode, t.getToken());
            } catch (Exception e) {
                ApiAssert.failure("解密注册码错误");
            }
            ApiAssert.isNotEmpty("解析注册码为空", code);
            AuthToken authToken = arcAuthTokenService.getLicense();
            ApiAssert.isNotEmpty("解析License异常", authToken);
            if (!code.equals(authToken.getCode())) {
                ApiAssert.failure("License与注册码不匹配");
            }
//            redisUtils.del(AuthTokenProvider.authTokenRedisKey);
        }
        return ResultBody.ok("更新成功", t);
    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, ArcSetting t, EntityMap extra) {
        //ArcSetting obj = this.baseMapper.selectById(t.getSettingId());
//        redisUtils.del(ArchiveConstants.REDIS_SETTING_KEY_PREFIX+obj.getBindUrl());
//        redisUtils.del(ArchiveConstants.REDIS_SETTING_KEY_PREFIX);
        EntityMap setting = findByTenant();
        if (FlymeUtils.isNotEmpty(setting)) {
            redisUtils.set(ArchiveConstants.REDIS_SETTING_KEY_PREFIX, setting, 60 * 30L);
        }
        return ResultBody.ok("更新成功", t);
    }

    @Override
    public ResultBody checkToken() {

        return arcAuthTokenService.checkTokenCode();
    }

    /**
     * 获取默认版本配置
     *
     * @param param
     * @return
     */
    @Override
    public ResultBody getDefaultArcSetting(Map param) {
        //TODO saas 需要修改
        Object obj = redisUtils.get(ArchiveConstants.REDIS_SETTING_KEY_PREFIX);
        AuthToken authToken = null;
        try {
            authToken = arcAuthTokenService.getLicense();
        } catch (Exception e) {

        }

        Map objMap = null;
        if (FlymeUtils.isNotEmpty(obj)) {
            objMap = (Map) obj;
        } else {
            objMap = findByTenant();
        }

        Object idCode = objMap.get("idCode");
        String idCodeStr = checkIdCode(FlymeUtils.isEmpty(idCode) ? null : idCode.toString()
                , Long.parseLong(objMap.get("settingId").toString()));
        objMap.put("idCode", idCodeStr);

        if (FlymeUtils.isNotEmpty(authToken)) {
            objMap.putAll(BeanUtil.beanToMap(authToken, false, true));
            objMap.put("expire", 0);
            redisUtils.set(ArchiveConstants.REDIS_SETTING_KEY_PREFIX, objMap, 60 * 60 * 30L);
        } else {
            objMap.put("expire", 1);
        }
        //objMap.put("isActivation", (ErrorCode.OK.getCode() == arcAuthTokenService.checkTokenCode().getCode() ? 1 : 0));
        objMap.put("isActivation", StrUtil.isNotEmpty(objMap.get("token").toString()) ? 1 : 0);

        return ResultBody.ok(objMap);
    }

    private String checkIdCode(String idCode, Long settingId) {
        String sysId = null;
        String noSysIdCode = redisUtils.getString("noSysIdCode");
        if (FlymeUtils.isEmpty(noSysIdCode)) {
            synchronized (this) {//同步获取机器码  防止
                sysId = getIdCode();
                if ("default".equals(sysId)) {//获取机器码异常或空
                    sysId = IdWorker.getIdStr();
                    redisUtils.set("noSysIdCode", sysId);
                }
            }
        } else {
            sysId = noSysIdCode;
        }
        if (FlymeUtils.isEmpty(idCode) || !idCode.equals(sysId)) {
            idCode = sysId;
            LambdaUpdateWrapper<ArcSetting> arcSettingLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            arcSettingLambdaUpdateWrapper.set(ArcSetting::getIdCode, idCode).eq(ArcSetting::getSettingId, settingId);
            this.update(arcSettingLambdaUpdateWrapper);
            redisUtils.del(ArchiveConstants.REDIS_SETTING_KEY_PREFIX);
        }
        return idCode;
    }

    private String getIdCode() {
        String idCode = redisUtils.getString(ArchiveConstants.REDIS_ID_CODE_KEY_PREFIX);
        if (FlymeUtils.isEmpty(idCode)) {
            try {
                idCode = ArcUtils.getMainBordId();
            } catch (Exception e) {
                log.error("获取用户识别码异常", e);
            }
        }
        if (FlymeUtils.isNotEmpty(idCode) && idCode.trim().length() > 7) {
            redisUtils.set(ArchiveConstants.REDIS_ID_CODE_KEY_PREFIX, idCode, 60 * 60 * 24L);
            return idCode;
        }
        return "default";

//        else{
//
//            idCode = IdWorker.getIdStr();
//            redisUtils.set(ArchiveConstants.REDIS_ID_CODE_KEY_PREFIX,idCode);
//            //ApiAssert.failure("获取用户识别码为空");
//            return idCode;
//        }
    }

    /**
     * 查询租户系统配置
     *
     * @return
     */
    @Override
    public EntityMap findByTenant() {
        CriteriaQuery<ArcSetting> cq = new CriteriaQuery(ArcSetting.class);
        cq.eq("isDefault", ArchiveEnumInteger.IS_DEFAULT.getCode());
//        cq.eq("bindUrl");
        List<EntityMap> list = selectEntityMap(cq);
        if (FlymeUtils.isNotEmpty(list)) {
            if (list.size() > 1) {
                ApiAssert.failure("系统存在多个默认配置，请联系管理员");
            }
            return list.get(0);
        }
        ApiAssert.isNotEmpty("系统没有默认配置", list);
        return null;
    }

    @Override
    public ResultBody uploadLicense(MultipartFile file) {
        try {
            String filePath = System.getProperty("user.dir");
            String tempFileName = System.currentTimeMillis() + "";
            File tempFile = new File(filePath + File.separator + tempFileName);
            file.transferTo(tempFile);
            AuthToken tempToken = arcAuthTokenService.readTokenFromTokenFile(tempFile);
            if (FlymeUtils.isNotEmpty(tempToken) && FlymeUtils.isNotEmpty(tempToken.getAuthTime())) {
                //
                redisUtils.del(AuthTokenProvider.licenseRedisKey);
                File f = new File(filePath + File.separator + AuthTokenProvider.licenseName);
                if (f.exists()) {
                    f.delete();
                }
                tempFile.renameTo(new File(filePath + File.separator + AuthTokenProvider.licenseName));
                AuthToken token = arcAuthTokenService.getLicense();

                if (FlymeUtils.isEmpty(token)) {
                    return ResultBody.failed("License为空或已过期");
                }
                redisUtils.set(AuthTokenProvider.tokenCodeRedisKey, token.getCode(), 60 * 60 * 3L);

                arcSettingService.update(new UpdateWrapper<ArcSetting>().eq("isDefault", ArchiveEnumInteger.IS_DEFAULT.getCode()).lambda().set(ArcSetting::getToken, ""));

                EntityMap setting = arcSettingService.findByTenant();
                if (FlymeUtils.isNotEmpty(setting)) {
                    redisUtils.set(ArchiveConstants.REDIS_SETTING_KEY_PREFIX, setting, 60 * 30L);
                }


                return ResultBody.ok(token);
            } else {
                return ResultBody.failed("license解析结果为空");
            }
        } catch (IOException e) {
            log.error("上传文件错误", e);
            ApiAssert.failure("上传license错误");
            return ResultBody.failed();
        }
    }
}
